package com.maben.vue_support.controller;

import cn.hutool.jwt.JWTUtil;
import com.alibaba.fastjson.JSON;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.maben.vue_support.aspect.annotation.LogDbRecord;
import com.maben.vue_support.aspect.pojo.OperateModule;
import com.maben.vue_support.aspect.pojo.OperateType;
import com.maben.vue_support.constant.CommonConstant;
import com.maben.vue_support.constant.Result;
import com.maben.vue_support.controller.vo.SysUserVo;
import com.maben.vue_support.service.ISysUserService;
import com.maben.vue_support.util.AesUtil;
import com.maben.vue_support.util.PasswordUtil;
import com.maben.vue_support.util.RedisUtil;
import com.maben.vue_support.util.TokenUtil;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.util.*;

/**
 * 登录相关接口
 */
@RestController
@RequestMapping("login")
@Api(tags = "登录模块")
public class LoginController {

    @Resource
    private ISysUserService sysUserService;


    /**
     * 获取加密字符串
     */
    @ApiOperation(value = "获取加密字符串")
    @GetMapping(value = "/getEncryptedString")
    public Result getEncryptedString() {
        final Map<String, String> map = new HashMap<>();
        map.put("key", CommonConstant.AES_KEY);
        map.put("iv", CommonConstant.AES_IV);
        return Result.OK(map);
    }

    /**
     * 处理用户登录逻辑
     */
    @PostMapping("handleLogin")
    @ApiOperation(value = "处理登录接口")
    @LogDbRecord(description = "处理登录接口", operateType = OperateType.OPERATE_TYPE_LOGIN, operateModule = OperateModule.登录模块)
    @ApiOperationSupport(includeParameters = {"userVo.username", "userVo.password"})
    public Result<SysUserVo> handleLogin(@RequestBody SysUserVo userVo) throws Exception {
        final String username = Objects.nonNull(userVo.getUsername()) ? userVo.getUsername().trim() : null;
        final String password = Objects.nonNull(userVo.getPassword()) ? userVo.getPassword().trim() : null;
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            throw new Exception("username is empty || password is empty");
        }
        //解密password
        String passwordMW = null;
        try {
            passwordMW = AesUtil.decryptFromBase64(password);
        } catch (Exception e) {
            throw new Exception("decrypt password error:" + e.getMessage());
        }
        //通过用户名获取用户信息
        final Map<String, Object> cxMap = new HashMap<>();
        cxMap.put("username", username);
        final List<SysUserVo> list = sysUserService.queryUserListSelective(cxMap);
        if (list.size() == 0) {
            throw new Exception("userInfo is empty by username:" + username);
        }
        final SysUserVo sysUserVo = list.get(0);
        //校验用户密码
        final String userPassword = sysUserVo.getPassword();
        if (!PasswordUtil.verify(passwordMW, userPassword)) {
            throw new Exception("password mismatch for username:" + username);
        }
        //检查用户是否被禁用
        final String enabled = sysUserVo.getEnabled();
        if (!StringUtils.equals(enabled, "1")) {
            throw new Exception("username:" + username + " is disabled.");
        }
        //检查部门是否被禁用
        final String deptStatus = sysUserVo.getDeptStatus();
        if (!StringUtils.equals(deptStatus, "1")) {
            throw new Exception("username:" + username + ":dept is disabled.");
        }
        //设置token
        final Map<String, Object> userMap = new HashMap<>();
        userMap.put("username", username);
        userMap.put("loginTime", System.currentTimeMillis());
        final String token = JWTUtil.createToken(userMap, CommonConstant.TOKEN_KEY.getBytes());
        sysUserVo.setToken(token);
        RedisUtil.set(CommonConstant.REDIS_USER_HEAD + username, JSON.toJSONString(sysUserVo), CommonConstant.REDIS_USER_TIMEOUT);
        return Result.OK(sysUserVo);
    }

    /**
     * 处理用户退出逻辑
     */
    @PostMapping("handleLogout")
    @ApiOperation(value = "处理登出接口")
    @LogDbRecord(description = "处理登出接口", operateType = OperateType.OPERATE_TYPE_LOGIN, operateModule = OperateModule.登录模块)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "token", value = "请求token", required = true, paramType = "header", dataTypeClass = String.class),
    })
    public Result handleLogout() throws Exception {
        final String username = TokenUtil.getUsernameFormRequest();
        if (StringUtils.isNotBlank(username)) {
            RedisUtil.del(CommonConstant.REDIS_USER_HEAD + username);
        }
        return Result.OK();
    }


    /**
     * 用户心跳检测接口
     */
    @PostMapping("checkHeartBeat")
    @ApiOperation(value = "用户心跳检测接口")
    @LogDbRecord(description = "用户心跳检测接口", operateType = OperateType.OPERATE_TYPE_SEARCH, operateModule = OperateModule.登录模块)
    @ApiOperationSupport(includeParameters = {"userVo.username"})
    public Result checkHeartBeat(@RequestBody SysUserVo userVo)throws Exception {
        final String username = Objects.nonNull(userVo.getUsername()) ? userVo.getUsername().trim() : null;
        if (StringUtils.isBlank(username) || StringUtils.isBlank(username.trim())) {
            throw new Exception("username is empty.");
        }
        final boolean exist = RedisUtil.hasKey(CommonConstant.REDIS_USER_HEAD + username);
        return Result.OK(exist);
    }

    /**
     * 获取当前用户在线数量
     */
    @GetMapping("userCountOnline")
    @ApiOperation(value = "获取当前用户在线数量")
    @LogDbRecord(description = "获取当前用户在线数量", operateType = OperateType.OPERATE_TYPE_SEARCH, operateModule = OperateModule.登录模块)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "token", value = "请求token", required = true, paramType = "header", dataTypeClass = String.class),
    })
    public Result userCountOnline() {
        final Set<String> keys = RedisUtil.keys(CommonConstant.REDIS_USER_HEAD + "*");
        return Result.OK(keys.size());
    }

    /**
     * 获取当前用户在线数量
     */
    @PostMapping("getMenuList")
    @ApiOperation(value = "获取用户所属菜单")
    @LogDbRecord(description = "获取用户所属菜单", operateType = OperateType.OPERATE_TYPE_SEARCH, operateModule = OperateModule.登录模块)
    @ApiImplicitParams({
            @ApiImplicitParam(name = "token", value = "请求token", required = true, paramType = "header", dataTypeClass = String.class),
    })
    public Result getMenuList() {
        final String jsonStr = " [\n" +
                "      {\n" +
                "        id: \"1\",\n" +
                "        parentid: \"0\",\n" +
                "        name: \"首页\",\n" +
                "        icon: \"el-icon-s-home\",\n" +
                "        url: \"/home\",\n" +
                "      },\n" +
                "      {\n" +
                "        id: \"2\",\n" +
                "        parentid: \"0\",\n" +
                "        name: \"设备模块\",\n" +
                "        icon: \"el-icon-menu\",\n" +
                "        children: [\n" +
                "          {\n" +
                "            id: \"3\",\n" +
                "            parentid: \"2\",\n" +
                "            name: \"设备列表\",\n" +
                "            icon: \"el-icon-s-grid\",\n" +
                "            url: \"/dev/list\",\n" +
                "          },\n" +
                "          {\n" +
                "            id: \"4\",\n" +
                "            parentid: \"2\",\n" +
                "            name: \"导出分析\",\n" +
                "            icon: \"el-icon-share\",\n" +
                "            url: \"/dev/export\",\n" +
                "          },\n" +
                "        ],\n" +
                "      },\n" +
                "      {\n" +
                "        id: \"5\",\n" +
                "        parentid: \"0\",\n" +
                "        name: \"地图模块\",\n" +
                "        icon: \"el-icon-menu\",\n" +
                "        children: [\n" +
                "          {\n" +
                "            id: \"5-1\",\n" +
                "            parentid: \"5\",\n" +
                "            name: \"高德地图\",\n" +
                "            icon: \"el-icon-map-location\",\n" +
                "            url: \"/map/MapGaoDe\",\n" +
                "          },\n" +
                "          {\n" +
                "            id: \"5-2\",\n" +
                "            parentid: \"5\",\n" +
                "            name: \"百度地图\",\n" +
                "            icon: \"el-icon-map-location\",\n" +
                "            url: \"/map/MapBaiDu\",\n" +
                "          },\n" +
                "          {\n" +
                "            id: \"5-3\",\n" +
                "            parentid: \"5\",\n" +
                "            name: \"百度地图2\",\n" +
                "            icon: \"el-icon-map-location\",\n" +
                "            url: \"/map/MapBaiDu2\",\n" +
                "          },\n" +
                "          {\n" +
                "            id: \"5-4\",\n" +
                "            parentid: \"5\",\n" +
                "            name: \"Echarts地图\",\n" +
                "            icon: \"el-icon-map-location\",\n" +
                "            url: \"/map/MapEcharts\",\n" +
                "          },\n" +
                "        ],\n" +
                "      },\n" +
                "      {\n" +
                "        id: \"7\",\n" +
                "        parentid: \"0\",\n" +
                "        name: \"远程遥测\",\n" +
                "        icon: \"el-icon-thumb\",\n" +
                "        url: \"/remote/remoteCheck\",\n" +
                "      },\n" +
                "      {\n" +
                "        id: \"8\",\n" +
                "        parentid: \"0\",\n" +
                "        name: \"数据大屏\",\n" +
                "        icon: \"el-icon-s-marketing\",\n" +
                "        url: \"/bigScreen\",\n" +
                "      },\n" +
                "    ]";
        return Result.OK(JSON.parseArray(jsonStr));
    }


}
